1
|
7 |
|
import { |
2
|
|
|
BadRequestException, |
3
|
|
|
Controller, |
4
|
|
|
Param, |
5
|
|
|
ForbiddenException, |
6
|
|
|
Patch, |
7
|
|
|
Get, |
8
|
|
|
Body, |
9
|
|
|
Req, |
10
|
|
|
UseGuards, |
11
|
|
|
Request, |
12
|
|
|
} from '@nestjs/common'; |
13
|
7 |
|
import { UsersService } from './users.service'; |
14
|
7 |
|
import { UpdateTermsDto } from './dto/update-terms.dto/update-terms.dto'; |
15
|
7 |
|
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; |
16
|
7 |
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger'; |
17
|
7 |
|
import { UpdateUserDto } from './dto/update-user.dto/update-user.dto'; |
18
|
7 |
|
import { AdjustFundsDto } from './dto/update-user.dto/adjust-funds.dto'; |
19
|
7 |
|
import { AdminGuard } from '../auth/guards/admin.guard'; |
20
|
7 |
|
import { HTTP_STATUS } from '../constants/HTTP_responses'; |
21
|
7 |
|
import { |
22
|
|
|
ApiAuthResponses, |
23
|
|
|
ApiAdminResponses, |
24
|
|
|
ApiBadRequestResponse, |
25
|
|
|
} from 'src/decorators/api-responses.decorator'; |
26
|
|
|
|
27
|
7 |
|
export const CustomerExample = { |
28
|
|
|
githubId: '169550', |
29
|
|
|
username: 'three-musketeers', |
30
|
|
|
email: 'dasthreemusketö[email protected]', |
31
|
|
|
roles: ['user'], |
32
|
|
|
hasAcceptedTerms: false, |
33
|
|
|
avatarUrl: 'https://avatars.githubusercontent.com/u/169550?v=4', |
34
|
|
|
createdAt: '2024-12-01T05:01:01.000Z', |
35
|
|
|
updatedAt: '2024-12-07T18:30:30.000Z', |
36
|
|
|
} as const; |
37
|
|
|
|
38
|
|
|
@Controller({ path: 'users', version: '1' }) |
39
|
7 |
|
export class UsersController { |
40
|
12 |
|
constructor(private readonly usersService: UsersService) {} |
41
|
|
|
|
42
|
|
|
@Patch('terms') |
43
|
|
|
@UseGuards(JwtAuthGuard) |
44
|
|
|
@ApiBearerAuth() |
45
|
|
|
@ApiOperation({ summary: 'Update terms acceptance status' }) |
46
|
|
|
@ApiBody({ |
47
|
|
|
description: 'The body containing the updated terms acceptance status', |
48
|
|
|
type: UpdateTermsDto, |
49
|
|
|
}) |
50
|
|
|
@ApiResponse({ |
51
|
|
|
status: HTTP_STATUS.OK, |
52
|
|
|
description: 'Terms acceptance status updated successfully', |
53
|
|
|
examples: { |
54
|
|
|
'application/json': { |
55
|
|
|
summary: 'Example of a successful terms update', |
56
|
|
|
value: { |
57
|
|
|
githubId: '12345', |
58
|
|
|
hasAcceptedTerms: true, |
59
|
|
|
}, |
60
|
|
|
}, |
61
|
|
|
}, |
62
|
|
|
}) |
63
|
|
|
@ApiBadRequestResponse() |
64
|
|
|
@ApiAuthResponses() |
65
|
7 |
|
async updateTerms(@Req() req, @Body() updateTermsDto: UpdateTermsDto) { |
66
|
7 |
|
if (typeof updateTermsDto.hasAcceptedTerms !== 'boolean') { |
67
|
2 |
|
throw new BadRequestException('Invalid input'); |
68
|
|
|
} |
69
|
5 |
|
return await this.usersService.updateTerms(req.user.githubId, updateTermsDto.hasAcceptedTerms); |
70
|
|
|
} |
71
|
|
|
// Fetch all customers |
72
|
|
|
@Get() |
73
|
|
|
@UseGuards(JwtAuthGuard, AdminGuard) |
74
|
|
|
@ApiBearerAuth() |
75
|
|
|
@ApiOperation({ summary: 'Get all customers (Only for admin)' }) |
76
|
|
|
@ApiResponse({ |
77
|
|
|
status: HTTP_STATUS.OK, |
78
|
|
|
description: 'List of customers', |
79
|
|
|
examples: { |
80
|
|
|
'application/json': { |
81
|
|
|
summary: 'Example of a list of customers', |
82
|
|
|
value: [CustomerExample], |
83
|
|
|
}, |
84
|
|
|
}, |
85
|
|
|
}) |
86
|
|
|
@ApiAuthResponses() |
87
|
|
|
@ApiAdminResponses() |
88
|
7 |
|
async getAllCustomers() { |
89
|
|
|
// return {userid: "hej1"}; |
90
|
1 |
|
return await this.usersService.findAll(); |
91
|
|
|
} |
92
|
|
|
// Fetch a customer by ID |
93
|
|
|
@Get(':githubId') |
94
|
|
|
@UseGuards(JwtAuthGuard, AdminGuard) |
95
|
|
|
@ApiBearerAuth() |
96
|
|
|
@ApiOperation({ summary: 'Get customer by id (Only for admin)' }) |
97
|
|
|
@ApiResponse({ |
98
|
|
|
status: HTTP_STATUS.OK, |
99
|
|
|
description: 'Customer details returned by id', |
100
|
|
|
examples: { |
101
|
|
|
'application/json': { |
102
|
|
|
summary: 'Example of a customer', |
103
|
|
|
value: CustomerExample, |
104
|
|
|
}, |
105
|
|
|
}, |
106
|
|
|
}) |
107
|
|
|
@ApiResponse({ |
108
|
|
|
status: HTTP_STATUS.NOT_FOUND, |
109
|
|
|
description: 'Customer not found', |
110
|
|
|
}) |
111
|
|
|
@ApiAdminResponses() |
112
|
|
|
@ApiAuthResponses() |
113
|
7 |
|
async getCustomerById(@Param('githubId') githubId: string) { |
114
|
4 |
|
return await this.usersService.findById(githubId); |
115
|
|
|
} |
116
|
|
|
// Update a customer by ID |
117
|
|
|
@Patch(':githubId') |
118
|
|
|
@UseGuards(JwtAuthGuard, AdminGuard) |
119
|
|
|
@ApiBearerAuth() |
120
|
|
|
@ApiOperation({ summary: 'Update customer by githubId (Only for admin)' }) |
121
|
|
|
@ApiParam({ |
122
|
|
|
name: 'githubId', |
123
|
|
|
description: 'The GitHub ID of the user', |
124
|
|
|
example: '12345', |
125
|
|
|
}) |
126
|
|
|
@ApiBody({ |
127
|
|
|
description: 'The body containing the updated user details', |
128
|
|
|
type: UpdateUserDto, |
129
|
|
|
}) |
130
|
|
|
@ApiResponse({ |
131
|
|
|
status: HTTP_STATUS.OK, |
132
|
|
|
description: 'Customer updated successfully', |
133
|
|
|
examples: { |
134
|
|
|
'application/json': { |
135
|
|
|
summary: 'Example of a successful customer update', |
136
|
|
|
value: { |
137
|
|
|
githubId: '12345', |
138
|
|
|
email: '[email protected]', |
139
|
|
|
roles: ['admin'], |
140
|
|
|
hasAcceptedTerms: true, |
141
|
|
|
}, |
142
|
|
|
}, |
143
|
|
|
}, |
144
|
|
|
}) |
145
|
|
|
@ApiResponse({ |
146
|
|
|
status: HTTP_STATUS.BAD_REQUEST, |
147
|
|
|
description: 'Invalid input with error message', |
148
|
|
|
}) |
149
|
|
|
@ApiResponse({ |
150
|
|
|
status: HTTP_STATUS.NOT_FOUND, |
151
|
|
|
description: 'Customer not found', |
152
|
|
|
}) |
153
|
|
|
@ApiAdminResponses() |
154
|
|
|
@ApiAuthResponses() |
155
|
7 |
|
async updateCustomer(@Param('githubId') githubId: string, @Body() updateUserDto: UpdateUserDto) { |
156
|
1 |
|
return this.usersService.update(githubId, updateUserDto); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
@Get(':githubId/account') |
160
|
|
|
@UseGuards(JwtAuthGuard) |
161
|
|
|
@ApiBearerAuth() |
162
|
|
|
@ApiOperation({ |
163
|
|
|
summary: 'Get account balance and accumulated cost', |
164
|
|
|
description: 'Returns the users balance and accumulated monthly payment cost.', |
165
|
|
|
}) |
166
|
|
|
@ApiResponse({ |
167
|
|
|
status: HTTP_STATUS.OK, |
168
|
|
|
description: 'Account details retrieved successfully.', |
169
|
|
|
}) |
170
|
7 |
|
async getAccountDetails(@Param('githubId') githubId: string, @Request() req: any) { |
171
|
4 |
|
const user = await this.usersService.findById(githubId); |
172
|
4 |
|
const authenticatedUser = req.user; |
173
|
|
|
|
174
|
|
|
// Only allow if the user is an admin or viewing their own account |
175
|
4 |
|
if (authenticatedUser.githubId !== githubId && !authenticatedUser.roles.includes('admin')) { |
176
|
1 |
|
throw new ForbiddenException("You are not allowed to view other users' accounts."); |
177
|
|
|
} |
178
|
|
|
|
179
|
3 |
|
return { |
180
|
|
|
balance: user.balance, |
181
|
|
|
accumulatedCost: user.accumulatedCost, |
182
|
|
|
isMonthlyPayment: user.isMonthlyPayment, |
183
|
|
|
}; |
184
|
|
|
} |
185
|
|
|
@Patch(':githubId/adjust-funds') |
186
|
|
|
@UseGuards(JwtAuthGuard) |
187
|
|
|
@ApiBearerAuth() |
188
|
|
|
@ApiOperation({ |
189
|
|
|
summary: 'Adjust user balance and payment mode', |
190
|
|
|
description: 'Set a new balance for the user and optionally toggle monthly payment mode.', |
191
|
|
|
}) |
192
|
|
|
@ApiResponse({ |
193
|
|
|
status: HTTP_STATUS.OK, |
194
|
|
|
description: 'User balance adjusted successfully', |
195
|
|
|
}) |
196
|
|
|
@ApiResponse({ |
197
|
|
|
status: HTTP_STATUS.NOT_FOUND, |
198
|
|
|
description: 'User not found', |
199
|
|
|
}) |
200
|
|
|
@ApiAdminResponses() |
201
|
7 |
|
async adjustFunds( |
202
|
|
|
@Param('githubId') githubId: string, |
203
|
|
|
@Body() adjustFundsDto: AdjustFundsDto, |
204
|
|
|
@Request() req: any, |
205
|
|
|
) { |
206
|
5 |
|
const authenticatedUser = req.user; |
207
|
|
|
|
208
|
|
|
// Only allow if the user is an admin or adjusting their own account |
209
|
5 |
|
if (authenticatedUser.githubId !== githubId && !authenticatedUser.roles.includes('admin')) { |
210
|
1 |
|
throw new ForbiddenException("You are not allowed to adjust other users' accounts."); |
211
|
|
|
} |
212
|
|
|
|
213
|
4 |
|
return await this.usersService.adjustFunds(githubId, adjustFundsDto); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
@Patch(':githubId/soft-delete') |
217
|
|
|
@UseGuards(JwtAuthGuard, AdminGuard) |
218
|
|
|
@ApiBearerAuth() |
219
|
|
|
@ApiOperation({ summary: 'Soft delete a user (Only for admin - set user role to inactive)' }) |
220
|
|
|
@ApiResponse({ |
221
|
|
|
status: HTTP_STATUS.OK, |
222
|
|
|
description: 'User soft-deleted successfully', |
223
|
|
|
}) |
224
|
|
|
@ApiResponse({ |
225
|
|
|
status: HTTP_STATUS.NOT_FOUND, |
226
|
|
|
description: 'User not found', |
227
|
|
|
}) |
228
|
|
|
@ApiAdminResponses() |
229
|
7 |
|
async softDeleteUser(@Param('githubId') githubId: string) { |
230
|
3 |
|
return await this.usersService.softDeleteUser(githubId); |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|